﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using GameBase;

namespace GalaxyPresident
{
    public class Orbit : GameBase.VisibleGameEntity
    {
        private Vector2 _center;
        private float _a;
        private float _b;

        private double _n = 2;
        private double _m = 2;

        private List<Vector2> _pointsOfOrbit = new List<Vector2>();
        private float distance = 18;
        private Vector2 pointSize = new Vector2(2);

        private List<Vector2> _points = new List<Vector2>();

        private double randomAngleInit;

        public Vector2 Center
        {
            get { return _center; }
            set { _center = value; }
        }

        public double N
        {
            get { return _n; }
            set { _n = value; }
        }

        public double M
        {
            get { return _m; }
            set { _m = value; }
        }

        public Orbit(bool isLeftFocalCenter, float a, float b, float rotation)
        {
            rotate = rotation;

            Vector2 center;
            if (a > b)
                center = new Vector2((a-b) / 2, 0);
            else if (a < b)
                center = new Vector2(0, (b-a) / 2);
            else
                center = Vector2.Zero;
            if (!isLeftFocalCenter)
                center = -center;

            if(isLeftFocalCenter)
                center = rotatePoint(center, -rotate);
            else
                center = rotatePoint(center, rotate);

            _center = center;
            _a = a;
            _b = b;

            randomAngleInit = Constant.random.NextDouble() * Math.PI * 2;

            initOrbit();
        }

        public void addPoint(Vector2 point)
        {
            if (_points.Count > 50)
                _points.RemoveAt(0);
            _points.Add(point);
        }

        private Vector2 rotatePoint(Vector2 center, float rotatez)
        {
            // rotation fomular
            // =======================================
            //x' = Cos(Theta) * x - Sin(Theta) * y
            //y' = Cos(Theta) * y + Sin(Theta) * x
            // =======================================

            center.X = (float)(Math.Cos(rotatez) * center.X - Math.Sin(rotatez) * center.Y);
            center.Y = (float)(Math.Cos(rotatez) * center.Y + Math.Sin(rotatez) * center.X);
            return center;
        }

        public Vector2 getPositionAtAngle(double angle)
        {
            return getPositionAtAngle(angle+randomAngleInit,_a,_b);
        }
        public Vector2 getPositionAtAngle(double angle,double a, double b)
        {
            Vector2 result = Vector2.Zero;

            // orbit fomular
            // =======================================
            // x = |cos(t)|^(2/m)  * a * sgn(cos(t))
            // y = |sin(t)|^(2/n)  * b * sgn(sin(t))
            // sgn(param) = -1 if param < 0
            // sgn(param) = 0 if param = 0
            // sgn(param) = 1 if param > 0
            // =======================================

            result.X = (float)(Math.Pow(Math.Abs(Math.Cos(angle)), 2.0 / _m) * a * getSgn(Math.Cos(angle)));
            result.Y = (float)(Math.Pow(Math.Abs(Math.Sin(angle)), 2.0 / _n) * b * getSgn(Math.Sin(angle)));

            result += _center;

            result = rotatePoint(result, rotate);

            return result;
        }
        public override float Scale
        {
            get
            {
                return base.Scale;
            }
            set
            {
                base.Scale = value;
                initOrbit();
            }
        }
        public override float BaseScale
        {
            get
            {
                return base.BaseScale;
            }
            set
            {
                base.BaseScale = value;
                initOrbit();
            }
        }

        public void initOrbit()
        {
            _pointsOfOrbit.Clear();

            double a = _a * GetDrawScale();
            double b = _b * GetDrawScale();

            // c ~= Pi * [3*(a + b) - sqrt[(3*a + b)*(a + 3*b)]]
            double perimeter = Math.PI * (3 * (a + b) - Math.Sqrt((3 * a + b) * (a + 3 * b)));

            int n = (int)(perimeter / distance/GetDrawScale());
            double perAngle = 2 * Math.PI / n;

            for (int i = 0; i < n; i++)
            {
                _pointsOfOrbit.Add(getPositionAtAngle(perAngle * i + 1,a,b));
            }
        }

        private double getSgn(double param)
        {
            if (param < 0)
                return -1;
            if (param == 0)
                return 0;
            return 1;
        }

        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            base.Draw(gameTime, spriteBatch);

            if (isVisible)
            {
                Vector2 sizePoint = pointSize * GetDrawScale();
                if (sizePoint.X < 1 || sizePoint.Y < 1)
                    sizePoint = new Vector2(1);

                /*
                Constant.drawingContext.Begin();

                foreach (Vector2 pos in _pointsOfOrbit)
                {
                    Vector2 drawPos = pos + GetDrawPosition() + rotatePoint(Center * GetDrawScale() - Center, rotate);
                    Constant.drawingContext.DrawFilledEllipse(drawPos, sizePoint, Color.White);
                }
                //foreach (Vector2 pos in _points)
                //{
                //    Constant.drawingContext.DrawFilledEllipse(pos + GetDrawPosition() + (Center * GetDrawScale() - Center), sizePoint, Color.White);
                //}
                Constant.drawingContext.End();
                 */
                
            }
        }
    }
}
